package cn.itsource.user.service.impl;

import cn.itsource.basic.constant.UserConstants;
import cn.itsource.basic.exception.BusinessException;
import cn.itsource.basic.util.AjaxResult;
import cn.itsource.basic.util.HttpClientUtils;
import cn.itsource.basic.util.MD5Utils;
import cn.itsource.basic.util.StrUtils;
import cn.itsource.user.domain.Logininfo;
import cn.itsource.user.domain.User;
import cn.itsource.user.domain.WxUser;
import cn.itsource.user.dto.LoginDto;
import cn.itsource.user.mapper.LogininfoMapper;
import cn.itsource.user.mapper.UserMapper;
import cn.itsource.user.mapper.WxUserMapper;
import cn.itsource.user.service.ILoginService;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements ILoginService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private WxUserMapper wxUserMapper;
    @Autowired
    private UserMapper userMapper;


    @Override
    public Map<String, Object> accountLogin(LoginDto loginDto) {
        //1.校验
        // 1.1 空校验
        if(StringUtils.isEmpty(loginDto.getUsername()) || StringUtils.isEmpty(loginDto.getPassword()) ||
                StringUtils.isEmpty(loginDto.getType())){
             throw  new BusinessException("请输入完整信息！");
        }
        // 1.2 查询用户是否存在
        Logininfo info = logininfoMapper.loadByUser(loginDto);
        // 1.2.1 如果存在。校验密码
        if (info == null) {
            throw  new BusinessException("用户不存在！");
        }
        String salt = info.getSalt();
        String md5Pwd = MD5Utils.encrypByMd5(loginDto.getPassword() + salt);
        if (!md5Pwd.equals(info.getPassword())) {
            throw  new BusinessException("账号或密码错误！！");
        }
        // 1.2.2 禁用校验
        if(info.getDisable() != 1 ){
            throw  new BusinessException("账号已经被冻结，请联系客服！");
        }
        //2 登录成功
        // 2.1 生成token
        String token = UUID.randomUUID().toString();
        // 2.2 存redis
        redisTemplate.opsForValue().set(token, info, 30, TimeUnit.MINUTES);
        //3 返回 token loginInfo信息
        Map<String,Object> map = new HashMap<>();
        map.put("token", token);
        //4.作为高级技师的我们，应该前端用不到的敏感信息屏蔽掉
        info.setSalt(null);
        info.setPassword(null);
        map.put("logininfo",info);
        return map;
    }

    @Override
    public AjaxResult wechatLogin(String code) {
        //1.通过code拿token OAuth中第二步
        String getTokenUrl = UserConstants.GET_TOKEN_URL
                .replace("APPID", UserConstants.APPID)
                .replace("SECRET", UserConstants.SECRET)
                .replace("CODE", code);
        String tokenStr = HttpClientUtils.httpGet(getTokenUrl);
        if(StringUtils.isEmpty(tokenStr)){
            throw  new BusinessException("获取token失败！！");
        }
        //2.获取到token，已经自带了openid（微信号）
        JSONObject tokenObj = JSONObject.parseObject(tokenStr);
        String accessToken  = tokenObj.getString("access_token");
        String openId  = tokenObj.getString("openid");
        //3.查询t_wxuser ，看有有没有微信用户
        WxUser wxUser = wxUserMapper.loadByOpenId(openId);
        if(wxUser != null && wxUser.getUser_id() != null){//直接免密登录
            //3.1 如果有 + 绑定userId ：直接免密登录
            //登录成功
            Logininfo info = logininfoMapper.loadByUserId(wxUser.getUser_id());
            // 3.1.1  生成token
            String token = UUID.randomUUID().toString();
            // 3.1.2 存redis
            redisTemplate.opsForValue().set(token, info, 30, TimeUnit.MINUTES);
            //3.1.3 返回 token loginInfo信息
            Map<String,Object> map = new HashMap<>();
            map.put("token", token);
            //3.1.4.作为高级技师的我们，应该前端用不到的敏感信息屏蔽掉
            info.setSalt(null);
            info.setPassword(null);
            map.put("logininfo",info);
            return AjaxResult.me().setResultObj(map);
        }else{
            //3.2 如果没有 封装token + openid 返回前端，让它跳转到绑定页面
            String resultUrlParam = "accessToken="+accessToken+"&openId="+openId;
            return AjaxResult.me().setSuccess(false).setResultObj(resultUrlParam);
        }
    }

    @Override
    public Map<String, Object> wechatBinder(Map<String, String> param) {
        String accessToken = param.get("accessToken");
        String openId = param.get("openId");
        String phone = param.get("phone");
        String verifyCode = param.get("verifyCode");

        // 1)验证用户输入的信息有没有问题
        if(StringUtils.isEmpty(phone) || StringUtils.isEmpty(verifyCode)
                || StringUtils.isEmpty(accessToken)|| StringUtils.isEmpty(openId)){
            throw new BusinessException("请输入完整信息！");
        }
        // A 空校验
        // B 验证码是否过期
        Object codeObj = redisTemplate.opsForValue().get(UserConstants.BINDER_CODE_PREFIX + phone);
        //2 验证码校验  不要区分大小写
        if(codeObj == null){
            throw new BusinessException("验证码已失效，请重新获取！");
        }
        String code = ((String)codeObj).split(":")[0];
        if(!code.equalsIgnoreCase(verifyCode)){
            throw new BusinessException("验证码输入错误！");
        }
        // 2)查询用户有没有注册过
        User user = userMapper.loadByPhone(phone);
        // 如果没有注册过：
        Logininfo info = null;
        if(user == null){
        // 生成t_user和t_logininfo
            user = initUserByPhone(phone);
            info =  user2LoginInfo(user);
            logininfoMapper.save(info);
            user.setLogininfo_id(info.getId());
            userMapper.save(user);
        }else{
            //如果注册过了 把登录信息查询出来
            info = logininfoMapper.loadById(user.getLogininfo_id());
        }
        //3)通过token等信息，到微信查询微信用户信息
        String getUserUrl =  UserConstants.GET_WXUSER_URL
                .replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId);
        String wxUserStr = HttpClientUtils.httpGet(getUserUrl);
        //生成微信用户并绑定平台用户
        // 4) 绑定微信用户和平台用户
        WxUser wxUser = user2WxUser(wxUserStr, user);
        wxUserMapper.save(wxUser);
        //5) 免密登录成功
        String token = UUID.randomUUID().toString();
        // 存redis
        redisTemplate.opsForValue().set(token, info, 30, TimeUnit.MINUTES);
        //返回 token loginInfo信息
        Map<String,Object> map = new HashMap<>();
        map.put("token", token);
        //作为高级技师的我们，应该前端用不到的敏感信息屏蔽掉
        info.setSalt(null);
        info.setPassword(null);
        map.put("logininfo",info);
        return map;
    }

    private Logininfo user2LoginInfo(User user) {
        Logininfo info = new Logininfo();
        BeanUtils.copyProperties(user, info);
        info.setType(1);
        return info;
    }

    private User initUserByPhone(String phone) {
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        //生成随机32位的salt
        String salt = StrUtils.getComplexRandomString(32);
        String md5Pwd = MD5Utils.encrypByMd5(StrUtils.getComplexRandomString(6) + salt);
        user.setSalt(salt);
        user.setPassword(md5Pwd);
        return user;
    }

    private WxUser user2WxUser(String wxUserStr, User user) {
        //装换微信用户信息
        JSONObject jsonObject = JSONObject.parseObject(wxUserStr);
        WxUser wxUser =  new WxUser();
        wxUser.setUser_id(user.getId());
        wxUser.setOpenid(jsonObject.getString("openid"));
        wxUser.setNickname(jsonObject.getString("nickname"));
        wxUser.setSex(jsonObject.getInteger("sex"));
        wxUser.setAddress(null);
        wxUser.setHeadimgurl(jsonObject.getString("headimgurl"));
        wxUser.setUnionid(jsonObject.getString("unionid"));
        return wxUser;
    }


}
